#include "stdafx.h"
#include "CppUnitTest.h"

#include <agents.h>
#include <string>
#include <iostream>
#include <sstream>

#include <Windows.h>

namespace cc {
  using namespace concurrency;
}

class Agent1 : public cc::agent
  {
  private:
    struct Impl
      {
        cc::ISource<int>& source;
        cc::ITarget<std::string>& target;

        Impl(cc::ISource<int>& s, cc::ITarget<std::string>& t)
          : source(s), target(t)
          {}
      } _ ;

  protected:

    void run()
      {
        std::stringstream ss;
        ss << "agent1: sending request ..." << std::endl;
        std::cout << ss.str();
        OutputDebugStringA(ss.str().c_str());

        send(_.target, std::string("request"));

        int response = receive(_.source);

        ss = std::stringstream();
        ss << "agent1: received '" << response << "'." << std::endl;
        std::cout << ss.str();
        OutputDebugStringA(ss.str().c_str());

        done();
      }

  public:
    explicit Agent1(cc::ISource<int>& source, cc::ITarget<std::string>& target)
      : _(source, target)
      {}
  };

class Agent2 : public cc::agent
  {
  private:
    struct Impl
      {
        cc::ISource<std::string>& source;
        cc::ITarget<int>& target;

        Impl(cc::ISource<std::string>& s, cc::ITarget<int>& t)
          : source(s), target(t)
          {}
      } _ ;

  protected:
    void run()
      {
        std::string request = receive(_.source);

        std::stringstream ss;
        ss << "agent2: received '" << request << "'." << std::endl;
        std::cout << ss.str();
        OutputDebugStringA(ss.str().c_str());

        ss = std::stringstream();
        ss << "agent2: sending responce ..." << std::endl;
        std::cout << ss.str();
        OutputDebugStringA(ss.str().c_str());

        send(_.target, 42);

        done();
      }

  public:
    explicit Agent2(cc::ISource<std::string>& source, cc::ITarget<int>& target)
      : _(source, target)
      {}
  };


using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace UnitTests
{
	TEST_CLASS(Cpp_AgentsLibrary_Tests)
	{
	public:
		
		TEST_METHOD(Test_Agents)
		{
			cc::unbounded_buffer<std::string>  buffer1;
      cc::overwrite_buffer<int>          buffer2;

      Agent1 agent1(buffer2, buffer1);
      Agent2 agent2(buffer1, buffer2);

      agent1.start();
      agent2.start();

      cc::agent::wait(&agent1);
      cc::agent::wait(&agent2);
		}

	};
}